package com.heima.search.service.impl;

import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.util.JsonUtils;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.search.service.MySearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.redisson.misc.Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class MySearchServiceImpl implements MySearchService {

    @Autowired
    private RestHighLevelClient highLevelClient;

    private String indexName = "app_info_article";

    /**
     * 把数据库数据导入Es
     * @param articleDtoList
     */
    @Override
    public void createIndex(List<ArticleDto> articleDtoList) {

//        批量操作对象
        BulkRequest bulkRequest = new BulkRequest();
        for (ArticleDto articleDto : articleDtoList) {
            Map<String,Object> map = new HashMap<>();
            map.put("id",articleDto.getId());
            map.put("publishTime",articleDto.getPublishTime());
            map.put("layout",articleDto.getLayout());
            map.put("images",articleDto.getImages());
            map.put("staticUrl",articleDto.getStaticUrl());
            map.put("authorName",articleDto.getAuthorName());
            map.put("labels",articleDto.getLabels());
            map.put("channelName",articleDto.getChannelName());
            map.put("title",articleDto.getTitle());
            map.put("content",articleDto.getContent());
//            把文档数据写bulkRequest
            IndexRequest indexRequest = new IndexRequest(indexName).id(articleDto.getId().toString());
//            把map转jison
            String jsonStr = JsonUtils.toString(map);
            indexRequest.source(jsonStr, XContentType.JSON);
            bulkRequest.add(indexRequest);
        }
        try {
            highLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("导入数据库的数据失败");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }


    }

    /**
     * 关键词搜索
     * @param dto
     * @return
     */
    @Override
    public List<ArticleDto> search(UserSearchDto dto) {

        String searchWords = dto.getSearchWords();
        if(StringUtils.isBlank(searchWords)){
            log.error("没有关键词");
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID);
        }
//        封装搜索请求
        SearchRequest searchRequest = new SearchRequest(indexName);

//        使用bool组合查询进行条件搜索
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        必须包含关键词搜索
        boolQueryBuilder.must(
                QueryBuilders.multiMatchQuery(searchWords,
                "title","content","labels"));
        if(dto.getMinBehotTime() != null){
            boolQueryBuilder.filter(
                    QueryBuilders.
                            rangeQuery("publishTime").lte(dto.getMinBehotTime()));
        }
//        把搜索条件放入请求对象
        searchRequest.source().query(boolQueryBuilder);
//        设置排序
        searchRequest.source().sort("publishTime", SortOrder.DESC);
//         分页
        searchRequest.source().from(dto.getFromIndex());
        searchRequest.source().size(dto.getPageSize());
//        高亮
        HighlightBuilder builder = new HighlightBuilder();
        builder.preTags("<em>");
        builder.field("title");
        builder.postTags("</em>");
        builder.requireFieldMatch(false);
        searchRequest.source().highlighter(builder);

//        关键搜索,把请求发给es服务端
        try {
            SearchResponse response = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            List<ArticleDto> list = new ArrayList<>();
            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
//                获取文档原始内容，json的字符串
                String jsonStr = hit.getSourceAsString();
//                把json字符串转对象
                ArticleDto articleDto = JsonUtils.toBean(jsonStr, ArticleDto.class);
//                处理高亮的结果
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField field = highlightFields.get("title");
//                高亮的结果
                String highTitle = field.getFragments()[0].toString();
                log.info("highTitle=={}",highTitle);
                articleDto.setTitle(highTitle);
                list.add(articleDto);
            }
            return list;
        } catch (IOException e) {
            log.error("es搜索异常");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }
}
